const express = require('express');
// const fs = require('fs');
const path = require('path');
const os = require('os')
const axios = require('axios');
const ChildProcess = require('child_process');
const bodyParser = require('body-parser')
let jsonParser = bodyParser.json({ limit: '1mb' })
let urlencodedParser = bodyParser.urlencoded({ extended: false })
const { PromisifyExec } = require('../lib')

const ROSLIB = require('roslib');
const ROS_NAMESPACE = '/ubiquityrobot/'

class ros_client {
  constructor(ros_base_ip, btnHandler = null) {
    this.url = 'ws://' + ros_base_ip + ':9090'
    this.ip = ros_base_ip
    this.ros = null
    // this.conectToRos()
  }

  conectToRos(onConnected, onFail) {
    console.log('trying to conect to ros server:')
    try {
      var ros = new ROSLIB.Ros({
        url: this.url
      });
    } catch (e) {
      console.log('ros client init error:', e)
      return
    }

    ros.on('connection', () => {
      console.log('Connected to websocket server.');

      if (onConnected) {
        onConnected()
      }
    });

    ros.on('error', function (error) {
      console.log('Error connecting to websocket server: ', error);
      if (onFail) {
        onFail()
      }
    });

    ros.on('close', () => {
      console.log('Connection to websocket server closed.');

      return

    });

    this.ros = ros
  }
  isConnected() {
    return this.ros && this.ros.isConnected
  }
  close() {
    this.ros.close()
  }

  variableList() {
    return new Promise((resolve) => {
      var client = new ROSLIB.Service({
        ros: this.ros,
        name: ROS_NAMESPACE + 'pi_driver_node/variable_list',
        serviceType: 'pi_driver/GetString'
      });

      var request = new ROSLIB.ServiceRequest({
      });
      client.callService(request, (result) => {
        console.log(result)
        resolve(result.data)
      });
    })
  }

  setVariable(key, value) {
    return new Promise((resolve) => {
      var client = new ROSLIB.Service({
        ros: this.ros,
        name: ROS_NAMESPACE + 'pi_driver_node/set_variable',
        serviceType: 'pi_driver/SetString'
      });

      var request = new ROSLIB.ServiceRequest({
        data: JSON.stringify({ key, value })
      });
      client.callService(request, (result) => {
        console.log(result)
        resolve(result.data)
      });
    })
  }

  deleteVariable(data) {
    return new Promise((resolve) => {
      var client = new ROSLIB.Service({
        ros: this.ros,
        name: ROS_NAMESPACE + 'pi_driver_node/delete_variable',
        serviceType: 'pi_driver/SetString'
      });

      var request = new ROSLIB.ServiceRequest({
        data
      });
      client.callService(request, (result) => {
        console.log(result)
        resolve(result.data)
      });
    })
  }

}

var ros = new ros_client('localhost')
let msgTopic

var setParam = () => {
  // Create a Param object for the max linear speed
  var param = new ROSLIB.Param({
    ros: ros.ros,
    name: 'reloaded',
  });
  console.log('trying to set ros param')
  axios.get('http://localhost:8000/rosNode/start_pi_node')
  param.set(false)
  // Get the value of the max linear speed paramater
  msgTopic = new ROSLIB.Topic({
    ros: ros.ros,
    name: ROS_NAMESPACE + 'pi_driver_node/new_message',
    messageType: 'std_msgs/String'
  });
  param.get(function (value) {
    console.log('get ros param', param.name, value)
  });
}

var onConnectFail = () => {

  console.log('connect Fail, retry after 3 seconds')

  setTimeout(() => {
    ros.conectToRos(setParam, onConnectFail)
  }, 3000)
}

ros.conectToRos(setParam, onConnectFail)

const router = express.Router();

const save_dir = path.join(os.homedir(), 'Lepi_Data')
const save_file = path.join(save_dir, '.variable.yaml')

const ns = '/variable'

router.get('/get', function (req, res) {
  try {
    ros.variableList().then(data => {
      res.send(data)
    })
  } catch (error) {
    res.json({ code: -1, msg: 'Failed' })
  }
})


router.get('/set', function (req, res) {
  const name = req.query['name']
  if (name == undefined) {
    res.json({ code: -2, msg: 'Error' })
    return
  }
  const value = req.query['value']
  if (value == undefined) {
    res.json({ code: -3, msg: 'Error' })
    return
  }
  try {
    ros.setVariable(name, value).then(out => {
      res.json({ code: 0, msg: 'OK' })
    })
  } catch (error) {
    res.json({ code: -1, msg: 'Failed' })
  }
})

router.get('/delete', function (req, res) {
  const name = req.query['name']
  if (name == undefined) {
    res.json({ code: -2, msg: 'Failed' })
    return
  }
  try {
    ros.deleteVariable(name).then(async (out) => {
      res.json({ code: 0, msg: 'OK' })
      await PromisifyExec('rosparam dump ' + save_file + ' /variable')
    })
  } catch (error) {
    res.json({ code: -1, msg: 'Failed' })
  }
})

router.get('/save', function (req, res) {
  try {
    PromisifyExec('rosparam dump ' + path.join(save_dir, '.variable.yaml') + ' /variable').then(out => {
      res.json({ code: 0, msg: 'OK' })
    })
  } catch (error) {
    res.json({ code: -1, msg: 'Failed' })
  }
})

router.post('/message', jsonParser, urlencodedParser, function (req, res) {
  try {
    console.log(req.socket.remoteAddress, req.body)
    let patern = /(\d{1,3}\.){3}\d{1,3}/g
    let from = req.socket.remoteAddress.match(patern)
    if (from && from.length >= 1) {
      from = from[0]
    } else {
      from = req.socket.remoteAddress
    }
    var msg = new ROSLIB.Message({
      data: JSON.stringify({ ...req.body, from: from })
    });

    msgTopic.publish(msg)
    res.json({ code: 0, msg: 'Success' })
  } catch (error) {
    console.log(error)
    res.json({ code: -1, msg: 'Failed' })
  }
})

module.exports = router